//7．修改程序清单14.14，从文件中读取每条记录并显示出来，
//允许用户删除记录或修改记录的内容。
//如果删除记录，把空出来的空间留给下一个要读入的记录。
//要修改现有的文件内容，必须用"r+b"模式，而不是"a+b"模式。
//而且，必须更加注意定位文件指针，防止新加入的记录覆盖现有记录。
//最简单的方法是改动储存在内存中的所有数据，然后再把最后的信息写入文件。
//跟踪的一个方法是在book结构中添加一个成员表示是否该项被删除。

/* booksave.c -- saves structure contents in a file */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define MAXTITL  40
#define MAXAUTL  40
#define MAXBKS   10             /* maximum number of books */

char *s_gets(char *st, int n);

struct book {                   /* set up book template    */
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

static void eatline();

static int get_operation();

static int get_opt_book_numb(int min, int max);

static void show_data(struct book books[], int size);

static void delete_item(struct book books[], int size, int pos);

static void set_item(struct book *book);

static void save_data(FILE *fp, struct book books[], int size);

static int get_i() {
    int i;
    int s = scanf("%d", &i);
    eatline();
    if (s != 1)return 0;
    return i;
}

int main(void) {
    struct book library[MAXBKS]; /* array of structures     */
    int count = 0;
    FILE *pbooks;
    int size = sizeof(struct book);

    if ((pbooks = fopen("../unit14/book.dat", "r+b")) == NULL) {
        fputs("Can't open book.dat file\n", stderr);
        exit(1);
    }
    //get data from file
    rewind(pbooks);            /* go to start of file     */
    while (count < MAXBKS && fread(&library[count], size,
                                   1, pbooks) == 1) {
        if (count == 0)
            puts("Current contents of book.dat:");
        printf("%s by %s: $%.2f\n", library[count].title,
               library[count].author, library[count].value);
        count++;
    }
    if (count == MAXBKS) {
        exit(2);
    }
    while (true) {
        show_data(library, count);
        int op = get_operation();
        switch (op) {
            case 1: //添加一本书
                if (count == MAXBKS) {
                    fputs("The book.dat file is full.", stderr);
                }
                set_item(&library[count]);
                count++;
                break;
            case 2:
                set_item(&library[get_opt_book_numb(0, count - 1)]);
                break;
            case 3:
                delete_item(library, count, get_opt_book_numb(0, count - 1));
                count--;
                break;
            case 4:
                save_data(pbooks, library, count);
                return 0;
            case 5:
                return 0;
        }
    }
}

char *s_gets(char *st, int n) {
    char *ret_val;
    char *find;

    ret_val = fgets(st, n, stdin);
    if (ret_val) {
        find = strchr(st, '\n');   // look for newline
        if (find)                  // if the address is not NULL,
            *find = '\0';          // place a null character there
        else
            while (getchar() != '\n')
                continue;          // dispose of rest of line
    }
    return ret_val;
}


static void show_data(struct book books[], int size) {
    puts("************************************************************************************");
    printf("%-10s%-20s%-20s%-10s\n", "optnumb", "book_title", "book_author", "book_value");
    for (int i = 0; i < size; ++i) {
        printf("%-10d%-20s%-20s%-10.2f\n", i, books[i].title, books[i].author, books[i].value);
    }
    puts("************************************************************************************");
}

static int get_operation() {
    puts("******************************************");
    puts("Select your operation");
    puts("1)Add new book\t\t2)Update a book");
    puts("3)Delete a book\t\t4)Save and exit");
    puts("5)Exit direct");
    puts("******************************************");
    int i;
    for (i = get_i(); i < 1 || i > 4; i = get_i()) {
        printf("请输入1-5:\n");
    }
    return i;
}

static int get_opt_book_numb(int min, int max) {
    printf("输入你要操作的书(%d-%d):", min, max);
    int i;
    for (i = get_i(); i < min || i > max; i = get_i()) {
        printf("只能输入%d-%d:", min, max);
    }
    return i;
}

static void set_item(struct book *book) {
    //add book
    puts("Please add new book titles.");
    s_gets(book->title, MAXTITL);
    puts("Now enter the author.");
    s_gets(book->author, MAXAUTL);
    puts("Now enter the value.");
    scanf("%f", &book->value);

}

static void delete_item(struct book books[], int size, int pos) {
    //将pos后面的item向前移
    for (int i = pos; i < size - 1; ++i) {
        books[i] = books[i + 1];
    }
}

static void save_data(FILE *pbooks, struct book library[], int count) {
    int index;
    if (count > 0) {
        rewind(pbooks);            /* go to start of file     */
        puts("Here is the list of your books:");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
        fwrite(library, sizeof(struct book), (size_t) count,
               pbooks);
    } else{
        puts("No books? Too bad.\n");
        FILE *file;
        if(file=fopen("../unit14/book.dat", "w+b")!=NULL){
            fclose(file);
        }
        fclose(pbooks);
    }

}

static void eatline() {
    while (getchar() != '\n')
        continue;/* clear input line  */
}
